#ifndef __GSM_MODEM_H_
#define __GSM_MODEM_H_


#include "gsm.h"


/******************************************/
/*                MODEM[配置]             */
/******************************************/

/* 短指令队列长度 */
#define MDM_SCMD_LIST_LENGTH        14

/* 短指令长度 */
#define MDM_SCMD_BLK_SIZE           64    /* 单位：byte */

/* 短指令缓存大小 */
#define MDM_TX_SBUFF_SIZE		        ( MDM_SCMD_LIST_LENGTH * MDM_SCMD_BLK_SIZE ) 

/* 长指令队列长度 */
#define MDM_LCMD_LIST_LENGTH        2

/* 长指令长度 */
#define MDM_LCMD_BLK_SIZE           200   /* 单位：byte */

/* 长指令缓存大小 */
#define MDM_TX_XBUFF_SIZE		        ( MDM_LCMD_LIST_LENGTH * MDM_LCMD_BLK_SIZE )

/* 临时指令收发缓冲区大小 */
#define MDM_RX_BUFF_SIZE_MAX		    1500   /* 单位：byte */
#define MDM_TX_BUFF_SIZE_MAX		    200   /* 单位：byte */



/* Common routines */
#define IS_AF(c)  ((c >= 'A') && (c <= 'F'))
#define IS_af(c)  ((c >= 'a') && (c <= 'f'))
#define IS_09(c)  ((c >= '0') && (c <= '9'))
#define ISVALIDHEX(c)  IS_AF(c) || IS_af(c) || IS_09(c)
#define ISVALIDDEC(c)  IS_09(c)
#define CONVERTDEC(c)  (c - '0')


typedef struct MDM_CMD_STRUCTER   MDM_CmdTypedef;
typedef struct MDM_RSP_STRUCTER   MDM_RspTypedef;

/* MDM参数[配置] */
typedef uint8_t MDM_RSP_ID;

/* Modem's status */
typedef enum {

	/* Modem is uninitialized
	 * Might also have once worked but timed out on AT command */
	MDM_UNINITIALIZED = 0,
	
	/* Modem's serial ports are initialized
	 * Waiting for initializing at commands to finish. */
	MDM_SERIAL_INIT,
	
	/* Modem is currently being initialized */
	MDM_INITIALIZING,
	
	/* Modem is ready to receive commands */
	MDM_READY,
	
	/* Modem is busy, and can't receive more commands */
	MDM_IS_BUSY,
	
	/* Modem should be resetted */
	MDM_RESET
} MDM_Status;


/* ID enum */ 
enum
{
    MDM_NO_STRING,  /* Unknown string */ 

    MDM_OK,         /* "OK" */ 
    MDM_BUSY,       /* "BUSY" */ 
    MDM_NO_ANSWER,  /* "NO ANSWER" */ 
    MDM_NO_CARRIER, /* "NO CARRIER" */ 
    MDM_CONNECT,    /* "CONNECT" */ 
    MDM_ERROR,      /* "ERROR" */ 
    MDM_CME_ERROR,  /* "+CME ERROR:" */ 
    MDM_CMS_ERROR,  /* "+CMS ERROR:" */ 
    MDM_CPIN,       /* "+CPIN:" */ 
    MDM_TIME_OUT,
    MDM_SEND_QUERY_OK,
    MDM_SEND_OK,

    MDM_LAST_TERMINAL,      /* All terminal responses are before this line */ 

    MDM_RING = MDM_LAST_TERMINAL,   /* "RING" */ 
    MDM_CRING,      /* "+CRING:" */ 
    MDM_CPINC,      /* "+CPINC:" */ 
    MDM_CMEE,       /* "+CMEE:" */ 
    MDM_CREG,       /* "+CREG:" */ 
    MDM_CGREG,      /* "+CGREG:" */ 
    MDM_CRC,        /* "+CRC:" */ 
    MDM_CGEV,       /* "+CGEV:" */ 
    MDM_CGEREP,     /* "+CGEREP:" */ 

    MDM_CEREG,
    MDM_IPR,
    MDM_COPS,
    MDM_CCLK,
    MDM_CFUN,
    MDM_CGSN,
    MDM_CGMR,
    MDM_CCID,
    MDM_FSCD,
    MDM_FSLS,
    MDM_CGMM,
    MDM_CGMI,
    MDM_CSQ,
    MDM_SIM,
    MDM_CMGR,
    MDM_CMGL,
    MDM_CNUM, 
    MDM_CIMI,
    MDM_CSCA,
    MDM_CMGW,
    MDM_CPAS,
    MDM_CPBR,
    MDM_CMUT,
    MDM_CLIP,
    MDM_CCWA,
    MDM_CMTI,
    MDM_CRSL,
    MDM_PIN,
    MDM_PUK,
    MDM_CGCLASS,
    MDM_CFTPSSTART,
    MDM_CFTPSLOGIN,
    MDM_CFTPSGETFILE,
    MDM_CGACT,
    MDM_CGDCONT,
    MDM_CGATT,
    MDM_CNSMOD,
    MDM_RECEIVE,		/* "+RECEIVE,"*/
    MDM_CIPOPEN,    /* "+CIPOPEN"*/
    /* Last string ID */ 
    MDM_LAST
};


/* AT command ids */
typedef enum 
{
    /* returns an alphanumeric string indicating the status 
    of the SIM card, and whether a password is 
    required or not. This is an independent 
    SIM card lock status check only, and does 
    not check the phone lock status. */
    PIN_QUERY=1,
    QUERY_SUBSCRIBER_NUMBERS,
    QUERY_SUBSCRIBER_NUMBERS_FROM_PHONEBOOK,
    REPLY_COMMAND,
    SOFT_RESET,
    ATT,
    DTR_SET,
    AUTO_ANSWER,
    COMMAND_ECHO,
    SET_OP_QUERY_REPLY,
    PIN_SETUP,
    PIN_CHANGE,
    PUK_SETUP,
    SET_PDU_MODE,
    SET_TXT_MODE,
    SET_OPERATOR,
    SET_OPERATOR_LOCKED,
    CUR_OP_QUERY,
    OPS_QUERY,
    POWER_ON,
    SOFTWARE_FOLW_CONTROL_ON,
    MODEM_STATUS_QUERY,
    NETWORK_REG_QUERY,
    NETWORK_CNSMOD_QUERY,
    NETWORK_REG_ENABLE,
    NETWORK_REGISTER,
    NETWORK_REGISTCNSMOD,
    GPRS_NETWORK_CGREG_QUERY,
    GPRS_NETWORK_CEREG_QUERY,
    SIGNAL_QUERY,
    ACTIVATE_CALL,
    QUERY_SEND_IDENTIFICATION,
    SET_SEND_IDENTIFICATION,
    CUR_CALLS_QUERY,
    CALL_RI_SET,
    CALL_RING,
    ACCEPT_CALL,
    HANGUP_CALLS,
    HANGUP_CURRENT,
    RELEASE_CALL,
    RELEASE_HELD,
    INITIATE_CALL,
    MUTE_QUERY,
    ENABLE_CLIP,
    ENABLE_CNMI,
    ENABLE_CMEE,
    ENABLE_CCWA,
    ENABLE_ECHO,
    DATA_TO_AT,
    AT_TO_DATA,
    READ_SERIAL_PORT_RATE,
    SET_SERIAL_PORT_RATE,
    SET_SERIAL_PORT_SLEEP,
    SET_DATE_TIME,
    DATE_TIME_QUERY,
    SMS_READ,
    SMS_SEND,
    SMS_STORE,
    SIM_SEND,
    SIM_RING_INDICATOR,
    SMS_DELETE,
    SMS_DELETE_ALL,
    SMS_SET_CENTER,
    SMS_CENTER_QUERY,
    SMS_LIST,
    SMS_INIT,
    RING_VOLUME_QUERY,
    SEND_DTMF,
    ESCAPE_COMMAND,
    RETURN_TO_DATA_STATE,
    SERVICE_BEARER_QUERY,
    SET_SERVICE_BEARER,
    CAPABILITIES_GET,
    MANUFACTURER_QUERY,
    MODEL_QUERY,
    SW_REVISION_QUERY,
    SIM_ICCID_QUERY,
    IMEI_QUERY,
    IMSI_QUERY,

    ATTACH_GPRS_NETWORK,
    DETACH_GPRS_NETWORK,
    GPRS_CONTEXT_ACT,
    GPRS_CONTEXT_NO_ACT,
    SOCKET_CONFIGURATION,
    SOCKET_CONFIGURATION_EXTERND,
    PPP_PARAM_CONFIG,
    SOCKET_DIAL,
    GPRS_SSEND,
    CFG_HTTP_PARAMS,
    CONTEXT_ACTIVATION,
    CONTEXT_ACT_CONFIG,
    DNS_CACH,
    REQUEST_LOCATION,

    SOCKET_SHUTDOWN,
    SOCKET_RESTORE,
    SOCKET_INACTIVE_TIMEOUT,
    SOCKET_SET,
    SOCKET_OPEN,
    SOCKET_CONFIGURE,
    SOCKET_TCP_SERVICE,
    SOCKET_TCP_CLOSE,
    PDP_QUERY_SEND_IsVALID,
    SELECT_FLOW_CONTROL,
    STAT_LED_GPIO_SET,
    LIST_GPRS_CLASSES,
    SELECT_GPRS_CLASS,
    ACTIVE_PDP_CONTEXT,
    DEACTIVE_PDP_CONTEXT,
    SELECT_PDP_CONTEXT,
    ADD_PDP_CONTEXT,
    CTCC_ADD_PDP_CONTEXT,
    DELETE_PDP_CONTEXT,
    LIST_PDP_CONTEXT,
    REQUEST_GPRS_SERVICE,


    VENDOR_COMMAND

} AtCommandID;

/**
 * @brief Symbol table struct, it is used by Scanner for token analysis
 */
typedef struct  
{
  ascii *symbol_name;
  uint32_t   symbol_token;
} SymbolTable;


typedef enum 
{
	/* Completed successfully */
  AT_HANDLER_DONE = 0,   
  
  /* Completed with an error from modem */
  AT_HANDLER_DONE_ERROR,
  
  /* Need more input(response) from modem */
  AT_HANDLER_NEED_MORE,
  
  /* Handler doesn't understand the input */
  AT_HANDLER_DONT_UNDERSTAND,
  
  /* Retry needed */
  AT_HANDLER_RETRY,           
  
  /* Unexpected error */
  AT_HANDLER_ERROR       
	
} AtCmdHandler_Status;

/* AtCommand handler function definition */
typedef AtCmdHandler_Status ( *AtCmdHandler ) ( MDM_CmdTypedef *at, MDM_RspTypedef *atrsp );

struct MDM_CMD_STRUCTER
{
	/* AtCommand id */
	uint32_t cmd_id;
	
	/* AtCommand buffer */
	ascii *AtBuffer;
	
	/* AtCommand timeout in milliseconds */
	uint32_t timeout;

	/* default retry count for the command */
	int16_t retry_counter;

	/* AT command response handle function */
	AtCmdHandler handler;
	
	/* Minimum sim state required for sending this command */
	SIM_Status required_state;

  /* Marked true when write is completed */
  bool write_complete; 
};



struct MDM_RSP_STRUCTER
{
  /* AtCommand has been finished */
	bool finish;

	/* Need more data */
	bool IsNeed;
	
  /* standard AtRsponse message */
	int16_t Code;

  /* revice AtRsponse message length */
	uint32_t totalsize;
	
	/* Already handled AtRsponse message length */
	uint32_t handledsize;

  /* AtRsponse buffer base pointer */
  ascii *indicator;
} ;

typedef struct Serialinterface Serial_IfTypedef;
typedef struct NetworkInterface Network_IfTypedef;
typedef struct PDPInterface PDP_IfTypedef;
typedef struct SIMInterface SIM_IfTypedef;

typedef struct {
	
  /* time out flag */
  bool is_timeout;
  
  /* SerialPlugin interface */
  Serial_IfTypedef *serial;

  /* Network interface */
  Network_IfTypedef *network;
    
  /* PDP Context interface */
  PDP_IfTypedef *pdp;
    
  /* SIM interface */
  SIM_IfTypedef *sim;

  /* Pointer to inter-process communication data */
  void *ipc_data;

  /* Does sim card need pin code before being able to send commands */
  SIM_Status sim_status;

  /* Handle to sms database */
  void* sms_handle;

  /* Is modem alive (responses to AT command) */
  MDM_Status status;
	
} MDM_DevTypedef;


typedef struct
{
    /* 计数器 */
    uint8_t shortCmdCounter;

    /* 计数器 */
    uint8_t longCmdCounter;

    /* 命令编号 */
    uint32_t shortCmdNumber;

    /* 命令编号 */
    uint32_t longCmdNumber;
    
    /* 命令队列结构 */ 
    struct  
    {
    /* 命令发送索引位置 */
    uint32_t CmdIndex;

    /* AT命令信息 */
    MDM_CmdTypedef At;
    } ShortCmd[ MDM_SCMD_LIST_LENGTH ], LongCmd[ MDM_LCMD_LIST_LENGTH ];

} MDM_CmdListCfgTypedef;



#define SHORT_CMD_COUNTER                 ( ready_cmd_list.shortCmdCounter )
#define SHORT_CMD_NUMBER                  ( ready_cmd_list.shortCmdNumber )
#define SHORT_CMD_INDEX( i )              ( ready_cmd_list.ShortCmd[ (i) ].CmdIndex )
#define SHORT_CMD( i )                    ( ready_cmd_list.ShortCmd[ (i) ].At )
#define SHORT_CMD_ID( i )                 ( ready_cmd_list.ShortCmd[ (i) ].At.cmd_id )
#define SHORT_CMD_STATE( i )              ( ready_cmd_list.ShortCmd[ (i) ].At.required_state )
#define SHORT_CMD_AT_BUFFER( i )          ( ready_cmd_list.ShortCmd[ (i) ].At.AtBuffer )

#define LONG_CMD_COUNTER                  ( ready_cmd_list.longCmdCounter )
#define LONG_CMD_NUMBER                   ( ready_cmd_list.longCmdNumber )
#define LONG_CMD_INDEX( i )               ( ready_cmd_list.LongCmd[ (i) ].CmdIndex )
#define LONG_CMD( i )                     ( ready_cmd_list.LongCmd[ (i) ].At )
#define LONG_CMD_ID( i )                  ( ready_cmd_list.LongCmd[ (i) ].At.cmd_id )
#define LONG_CMD_STATE( i )               ( ready_cmd_list.LongCmd[ (i) ].At.required_state )
#define LONG_CMD_AT_BUFFER( i )           ( ready_cmd_list.LongCmd[ (i) ].At.AtBuffer )

/******************************************/
/*            数据流控制[配置]            */
/******************************************/
#define MDM_FCM_V24_STATE_AT    0   /* AT状态 */
#define MDM_FCM_V24_STATE_DATA  1   /* 数据状态 */
#define MDM_FCM_V24_STATE_SW    2   /* 切换状态 */
#define MDM_FCM_V24_STATE_IDEL  10  /* 空闲态态 */

/* FCM Events */
typedef enum
{
  MDM_FCM_EVENT_FLOW_OPENNED,   /* 流打开事件 */
  MDM_FCM_EVENT_FLOW_CLOSED,    /* 流关闭事件 */
  MDM_FCM_EVENT_V24_DATA_MODE,  /* 流进入数据模式 */
  MDM_FCM_EVENT_V24_AT_MODE,    /* 流进入AT模式 */
  MDM_FCM_EVENT_RESUME,         /* 流接续事件 */
  MDM_FCM_EVENT_V24_DATA_MODE_FROM_CALL,  /* 流数据模式切换 */
  MDM_FCM_EVENT_V24_AT_MODE_FROM_CALL,    /* 流AT模式切换 */

  /* !!!以下事件为异常，使用服务时需要注意处理!!! */
  MDM_FCM_EVENT_SWITCH_TO,      /* 流切换超时事件 */
  MDM_FCM_EVENT_SWITCH_ERR,     /* 流切换失败事件 */
  MDM_FCM_EVENT_DIAL_ERR        /* 拨号失败事件 */
} mdm_fcmEvent_e;


/* 定义MODEM访问接口 */
extern MDM_DevTypedef *gsm_modem;


/* FCM control events handler */
typedef bool ( *mdm_fcmCtrlHdlr_f ) ( mdm_fcmEvent_e Event );


/* 函数声明 */
extern void MDM_IfInit ( MDM_DevTypedef *user_modem );

extern bool MDM_PostAtCmdByID( MDM_CmdTypedef *command, AtCommandID id, const ascii* params );

extern bool MDM_ReadData ( uint16_t DataSize, uint8_t *Data );

extern void SIM_ChangeAuthStatus ( void* ipc_data, SIM_Status status, const ascii *message, bool send_reply );

#endif


